/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include <gtest/gtest.h>
#include <mc/common.h>
#include <mc/memory.h>

#include "../../../../../drivers/chip/interface/i_chip.h"
#include "../../../../../drivers/internal/chip/chip_base/chip.h"
#include "../../../../../drivers/internal/bus/bus_base/bus.h"
#include "../../../../../drivers/internal/hasdef.h"
#include "../../internal/test_utils/mock_bus.h"

namespace {

// Mock chip_base 类，用于测试 Interface_Chip 的 IO 方法
class mock_chip_for_interface : public dev::chip_base {
public:
    mock_chip_for_interface() : m_host_bus(std::make_shared<test_utils::mock_bus>()) {
        set_host_bus(m_host_bus);
        m_bit_read_result = HAS_OK;
        m_bit_write_result = HAS_OK;
        m_block_read_result = HAS_OK;
        m_block_write_result = HAS_OK;
        m_block_write_read_result = HAS_OK;
        m_combo_block_write_read_result = HAS_OK;
    }

    void set_bit_read_result(int32_t result) {
        m_bit_read_result = result;
    }

    void set_bit_write_result(int32_t result) {
        m_bit_write_result = result;
    }

    void set_block_read_result(int32_t result) {
        m_block_read_result = result;
    }

    void set_block_write_result(int32_t result) {
        m_block_write_result = result;
    }

    void set_block_write_read_result(int32_t result) {
        m_block_write_read_result = result;
    }

    void set_combo_block_write_read_result(int32_t result) {
        m_combo_block_write_read_result = result;
    }

    void set_bit_read_output(const std::vector<uint8_t>& output) {
        m_bit_read_output = output;
    }

    void set_block_read_output(const std::vector<uint8_t>& output) {
        m_block_read_output = output;
    }

    void set_block_write_read_output(const std::vector<uint8_t>& output) {
        m_block_write_read_output = output;
    }

    void set_combo_block_write_read_output(const std::vector<uint8_t>& output) {
        m_combo_block_write_read_output = output;
    }

    void set_error_message(const std::string& error) {
        m_error_message = error;
    }

    int32_t bit_read(uint32_t offset, uint8_t length, uint32_t mask, std::vector<uint8_t>& in_buffer,
                      std::vector<uint8_t>& out_buffer, std::string& error) override {
        if (m_bit_read_result != HAS_OK) {
            error = m_error_message;
            return m_bit_read_result;
        }
        out_buffer = m_bit_read_output;
        if (out_buffer.size() < length) {
            out_buffer.resize(length, 0);
        }
        return HAS_OK;
    }

    int32_t bit_write(uint32_t offset, uint8_t length, uint32_t mask,
                       const std::vector<uint8_t>& buffer, std::vector<uint8_t>& out_buffer,
                       std::string& error) override {
        if (m_bit_write_result != HAS_OK) {
            error = m_error_message;
            return m_bit_write_result;
        }
        return HAS_OK;
    }

    int32_t block_read(uint32_t offset, uint32_t length, std::vector<uint8_t>& in_buffer,
                        std::vector<uint8_t>& out_buffer, std::string& error) override {
        if (m_block_read_result != HAS_OK) {
            error = m_error_message;
            return m_block_read_result;
        }
        out_buffer = m_block_read_output;
        if (out_buffer.size() < length) {
            out_buffer.resize(length, 0);
        }
        return HAS_OK;
    }

    int32_t block_write(uint32_t offset, const std::vector<uint8_t>& buffer,
                         std::vector<uint8_t>& out_buffer, std::string& error) override {
        if (m_block_write_result != HAS_OK) {
            error = m_error_message;
            return m_block_write_result;
        }
        return HAS_OK;
    }

    int32_t block_write_read(uint32_t mode, const std::vector<uint8_t>& indata, uint32_t read_length,
                               std::vector<uint8_t>& out_buffer, std::string& error) override {
        if (m_block_write_read_result != HAS_OK) {
            error = m_error_message;
            return m_block_write_read_result;
        }
        out_buffer = m_block_write_read_output;
        if (out_buffer.size() < read_length) {
            out_buffer.resize(read_length, 0);
        }
        return HAS_OK;
    }

    int32_t combo_block_write_read(uint32_t write_offset, const std::vector<uint8_t>& write_buffer,
                                     uint32_t read_offset, uint32_t read_length,
                                     std::vector<uint8_t>& in_buffer, std::vector<uint8_t>& out_buffer,
                                     std::string& error) override {
        if (m_combo_block_write_read_result != HAS_OK) {
            error = m_error_message;
            return m_combo_block_write_read_result;
        }
        out_buffer = m_combo_block_write_read_output;
        if (out_buffer.size() < read_length) {
            out_buffer.resize(read_length, 0);
        }
        return HAS_OK;
    }

private:
    std::shared_ptr<test_utils::mock_bus> m_host_bus;
    int32_t m_bit_read_result;
    int32_t m_bit_write_result;
    int32_t m_block_read_result;
    int32_t m_block_write_result;
    int32_t m_block_write_read_result;
    int32_t m_combo_block_write_read_result;
    std::vector<uint8_t> m_bit_read_output;
    std::vector<uint8_t> m_block_read_output;
    std::vector<uint8_t> m_block_write_read_output;
    std::vector<uint8_t> m_combo_block_write_read_output;
    std::string m_error_message;
};

// Test fixture
class i_chip_test : public ::testing::Test {
protected:
    void SetUp() override {
        m_mock_chip = std::make_shared<mock_chip_for_interface>();
        m_interface_chip = std::make_unique<dev::Interface_Chip>();
        m_interface_chip->m_chip = m_mock_chip.get();
    }

    void TearDown() override {
        m_interface_chip.reset();
        m_mock_chip.reset();
    }

    std::shared_ptr<mock_chip_for_interface> m_mock_chip;
    std::unique_ptr<dev::Interface_Chip> m_interface_chip;
};

// ========================= Interface_Chip from_variant 测试 =========================

TEST_F(i_chip_test, interface_chip_from_variant_all_fields) {
    // 目标：验证 from_variant 方法能够正确解析所有字段
    mc::mutable_dict csr_object;
    csr_object["Address"] = static_cast<uint32_t>(0x50);
    csr_object["OffsetWidth"] = static_cast<uint8_t>(2);
    csr_object["AddrWidth"] = static_cast<uint8_t>(1);
    csr_object["WriteTmout"] = static_cast<uint32_t>(1000);
    csr_object["ReadTmout"] = static_cast<uint32_t>(2000);
    csr_object["RwBlockSize"] = static_cast<uint8_t>(32);
    csr_object["WriteInterval"] = static_cast<uint8_t>(10);
    csr_object["ReadInterval"] = static_cast<uint8_t>(20);
    csr_object["WriteRetryTimes"] = static_cast<uint8_t>(3);
    csr_object["ReadRetryTimes"] = static_cast<uint8_t>(5);
    
    m_interface_chip->from_variant(csr_object);
    
    EXPECT_EQ(m_interface_chip->Address.get_value(), 0x50U);
    EXPECT_EQ(m_interface_chip->OffsetWidth.get_value(), 2U);
    EXPECT_EQ(m_interface_chip->AddrWidth.get_value(), 1U);
    EXPECT_EQ(m_interface_chip->WriteTmout.get_value(), 1000U);
    EXPECT_EQ(m_interface_chip->ReadTmout.get_value(), 2000U);
    EXPECT_EQ(m_interface_chip->RwBlockSize.get_value(), 32U);
    EXPECT_EQ(m_interface_chip->WriteInterval.get_value(), 10U);
    EXPECT_EQ(m_interface_chip->ReadInterval.get_value(), 20U);
    EXPECT_EQ(m_interface_chip->WriteRetryTimes.get_value(), 3U);
    EXPECT_EQ(m_interface_chip->ReadRetryTimes.get_value(), 5U);
}

TEST_F(i_chip_test, interface_chip_from_variant_partial_fields) {
    // 目标：验证 from_variant 方法能够处理部分字段缺失的情况
    
    mc::mutable_dict csr_object;
    // 只设置部分字段
    csr_object["Address"] = static_cast<uint32_t>(0x48);
    csr_object["OffsetWidth"] = static_cast<uint8_t>(1);
    
    m_interface_chip->from_variant(csr_object);
    
    EXPECT_EQ(m_interface_chip->Address.get_value(), 0x48U);
    EXPECT_EQ(m_interface_chip->OffsetWidth.get_value(), 1U);
    // 其他字段保持默认值（uint32_t 和 uint8_t 默认值为0）
}

TEST_F(i_chip_test, interface_chip_from_variant_empty_dict) {
    // 目标：验证 from_variant 方法能够处理空字典
    
    mc::mutable_dict csr_object;
    
    // 应该不会抛出异常，所有字段保持默认值
    EXPECT_NO_THROW(m_interface_chip->from_variant(csr_object));
}

TEST_F(i_chip_test, interface_chip_from_variant_invalid_type) {
    // 目标：验证 from_variant 方法在类型错误时抛出异常
    
    mc::mutable_dict csr_object;
    csr_object["Address"] = std::string("invalid");  // 应该是 uint32_t
    
    EXPECT_THROW(m_interface_chip->from_variant(csr_object), mc::parse_error_exception);
}

TEST_F(i_chip_test, interface_chip_from_variant_boundary_values) {
    // 目标：验证 from_variant 方法能够处理边界值
    
    mc::mutable_dict csr_object;
    csr_object["Address"] = static_cast<uint32_t>(0xFFFFFFFF);
    csr_object["OffsetWidth"] = static_cast<uint8_t>(255);
    csr_object["AddrWidth"] = static_cast<uint8_t>(255);
    csr_object["WriteTmout"] = static_cast<uint32_t>(0xFFFFFFFF);
    csr_object["ReadTmout"] = static_cast<uint32_t>(0xFFFFFFFF);
    csr_object["RwBlockSize"] = static_cast<uint8_t>(255);
    csr_object["WriteInterval"] = static_cast<uint8_t>(255);
    csr_object["ReadInterval"] = static_cast<uint8_t>(255);
    csr_object["WriteRetryTimes"] = static_cast<uint8_t>(255);
    csr_object["ReadRetryTimes"] = static_cast<uint8_t>(255);
    
    EXPECT_NO_THROW(m_interface_chip->from_variant(csr_object));
    
    EXPECT_EQ(m_interface_chip->Address.get_value(), 0xFFFFFFFFU);
    EXPECT_EQ(m_interface_chip->OffsetWidth.get_value(), 255U);
    EXPECT_EQ(m_interface_chip->AddrWidth.get_value(), 255U);
}

// ========================= Interface_Chip BitIORead 测试 =========================

TEST_F(i_chip_test, interface_chip_bitio_read_success) {
    // 目标：验证 BitIORead 方法在成功时返回正确数据
    std::vector<uint8_t> expected_output = {0x12, 0x34, 0x56};
    m_mock_chip->set_bit_read_output(expected_output);
    
    std::vector<uint8_t> result = m_interface_chip->BitIORead(0x10, 3, 0xFFFFFF);
    
    EXPECT_EQ(result.size(), 3);
    EXPECT_EQ(result, expected_output);
}

TEST_F(i_chip_test, interface_chip_bitio_read_failure) {
    // 目标：验证 BitIORead 方法在失败时抛出异常
    m_mock_chip->set_bit_read_result(HAS_ERR);
    m_mock_chip->set_error_message("bit read failed");
    
    EXPECT_THROW(m_interface_chip->BitIORead(0x10, 3, 0xFFFFFF), mc::method_call_exception);
}

// ========================= Interface_Chip BitIOWrite 测试 =========================

TEST_F(i_chip_test, interface_chip_bitio_write_success) {
    // 目标：验证 BitIOWrite 方法在成功时不抛出异常
    std::vector<uint8_t> write_data = {0x12, 0x34};
    
    EXPECT_NO_THROW(m_interface_chip->BitIOWrite(0x10, 2, 0xFFFF, write_data));
}

TEST_F(i_chip_test, interface_chip_bitio_write_failure) {
    // 目标：验证 BitIOWrite 方法在失败时抛出异常
    m_mock_chip->set_bit_write_result(HAS_ERR);
    m_mock_chip->set_error_message("bit write failed");
    std::vector<uint8_t> write_data = {0x12, 0x34};
    
    EXPECT_THROW(m_interface_chip->BitIOWrite(0x10, 2, 0xFFFF, write_data), mc::method_call_exception);
}

// ========================= Interface_Chip BlockIORead 测试 =========================

TEST_F(i_chip_test, interface_chip_blockio_read_success) {
    // 目标：验证 BlockIORead 方法在成功时返回正确数据
    std::vector<uint8_t> expected_output = {0xAA, 0xBB, 0xCC, 0xDD};
    m_mock_chip->set_block_read_output(expected_output);
    
    std::vector<uint8_t> result = m_interface_chip->BlockIORead(0x20, 4);
    
    EXPECT_EQ(result.size(), 4);
    EXPECT_EQ(result, expected_output);
}

TEST_F(i_chip_test, interface_chip_blockio_read_failure) {
    // 目标：验证 BlockIORead 方法在失败时抛出异常
    m_mock_chip->set_block_read_result(HAS_ERR);
    m_mock_chip->set_error_message("block read failed");
    
    EXPECT_THROW(m_interface_chip->BlockIORead(0x20, 4), mc::method_call_exception);
}

// ========================= Interface_Chip BlockIOWrite 测试 =========================

TEST_F(i_chip_test, interface_chip_blockio_write_success) {
    // 目标：验证 BlockIOWrite 方法在成功时不抛出异常
    std::vector<uint8_t> write_data = {0x11, 0x22, 0x33};
    
    EXPECT_NO_THROW(m_interface_chip->BlockIOWrite(0x20, write_data));
}

TEST_F(i_chip_test, interface_chip_blockio_write_failure) {
    // 目标：验证 BlockIOWrite 方法在失败时抛出异常
    m_mock_chip->set_block_write_result(HAS_ERR);
    m_mock_chip->set_error_message("block write failed");
    std::vector<uint8_t> write_data = {0x11, 0x22, 0x33};
    
    EXPECT_THROW(m_interface_chip->BlockIOWrite(0x20, write_data), mc::method_call_exception);
}

// ========================= Interface_Chip BlockIOWriteRead 测试 =========================

TEST_F(i_chip_test, interface_chip_blockio_write_read_success) {
    // 目标：验证 BlockIOWriteRead 方法在成功时返回正确数据
    std::vector<uint8_t> write_data = {0x01, 0x02};
    std::vector<uint8_t> expected_output = {0xAA, 0xBB};
    m_mock_chip->set_block_write_read_output(expected_output);
    
    std::vector<uint8_t> result = m_interface_chip->BlockIOWriteRead(write_data, 2);
    
    EXPECT_EQ(result.size(), 2);
    EXPECT_EQ(result, expected_output);
}

TEST_F(i_chip_test, interface_chip_blockio_write_read_failure) {
    // 目标：验证 BlockIOWriteRead 方法在失败时抛出异常
    m_mock_chip->set_block_write_read_result(HAS_ERR);
    m_mock_chip->set_error_message("block write read failed");
    std::vector<uint8_t> write_data = {0x01, 0x02};
    
    EXPECT_THROW(m_interface_chip->BlockIOWriteRead(write_data, 2), mc::method_call_exception);
}

// ========================= Interface_Chip BlockIOComboWriteRead 测试 =========================

TEST_F(i_chip_test, interface_chip_blockio_combo_write_read_success) {
    // 目标：验证 BlockIOComboWriteRead 方法在成功时返回正确数据
    std::vector<uint8_t> write_data = {0x01, 0x02};
    std::vector<uint8_t> expected_output = {0xCC, 0xDD};
    m_mock_chip->set_combo_block_write_read_output(expected_output);
    
    std::vector<uint8_t> result = m_interface_chip->BlockIOComboWriteRead(0x10, write_data, 0x20, 2);
    
    EXPECT_EQ(result.size(), 2);
    EXPECT_EQ(result, expected_output);
}

TEST_F(i_chip_test, interface_chip_blockio_combo_write_read_failure) {
    // 目标：验证 BlockIOComboWriteRead 方法在失败时抛出异常
    m_mock_chip->set_combo_block_write_read_result(HAS_ERR);
    m_mock_chip->set_error_message("combo block write read failed");
    std::vector<uint8_t> write_data = {0x01, 0x02};
    
    EXPECT_THROW(m_interface_chip->BlockIOComboWriteRead(0x10, write_data, 0x20, 2), mc::method_call_exception);
}

} // namespace

